/*
 * osobnik.h
 *
 * Copyright (C) 2008, 2009
 *
 * Lukasz Bieniasz-Krzywiec
 * Dariusz Leniowski
 *
 * Klasy osobnikow
 */

#ifndef OSOBNIK_H_
#define OSOBNIK_H_

#include "../config.h"

#include "random.h"
#include "historia.h"
#include "reputacja.h"
#include "fwwk.h"

extern int  N;
extern int  M;
extern int  REPUTACJA;
extern int  time;
extern rnd  *r;
extern fwwk *f;

class osobnik {
public:

  const int n;         // Jego numer w tablicy populacja
  const int rodzaj;    // Jaki jest jego rodzaj (ALLC, ALLD, etc.)
  const int utworzony; // Kiedy osobnik zostal utworzony (wg time)
  int       timestamp; // Zmienna pomocnicza, kiedy osobnik ostatni raz byl przeliczany

  /*
   * Strategia to liczba rzeczywista z przedzialu [0,1] oznaczajaca
   * prawdopodobienstwo, ze osobnik zagra w danej turze akcje C
   */
  historia<real>      strategia; // Historia strategii osobnika
  historia<real>      wyplata;   // Historia wyplat osobnika
  reputacja<osobnik>  *reputac;  // Modul zbierajacy reputacje

  real fitness;       // Przystosowanie osobnika, uzywane przez modul FITNESS
  real *krawedzie;    // Krawedzie w grafie sa to liczby rzeczywiste z przedzialu [0,1], gdzie 0 oznacza brak krawedzi, a 1 istnienie krawedzi

  /*
   * Funkcja zwraca nazwy osobnikow o podanym rodzaju.
   */
  static const char* nazwa(int r) {
    switch (r) {
      case OSOBNIK_ALLC:
        return "ALLC";
      case OSOBNIK_ALLD:
        return "ALLD";
      case OSOBNIK_NIETOPERZ_ZLY:
        return "NIETOPERZ_ZLY";
      case OSOBNIK_NIETOPERZ_DOBRY:
        return "NIETOPERZ_DOBRY";
      case OSOBNIK_ALLC_LOSOWO:
        return "ALLC_LOSOWO";
      case OSOBNIK_ALLC_WSZYSTO:
        return "ALLC_WSZYSTKO";
      case OSOBNIK_ALLC_WSPOLPRACA:
        return "ALLC_WSPOLPRACA1";
      case OSOBNIK_ALLC_WSPOLPRACA2:
        return "ALLC_WSPOLPRACA2";
      case OSOBNIK_ALLC_FITNESS:
        return "ALLC_FITNESS";
      case OSOBNIK_ALLD_LOSOWO:
        return "ALLD_LOSOWO";
      case OSOBNIK_ALLD_WSZYSTO:
        return "ALLD_WSZYSTKO";
      case OSOBNIK_ALLD_WSPOLPRACA:
        return "ALLD_WSPOLPRACA1";
      case OSOBNIK_ALLD_WSPOLPRACA2:
        return "ALLD_WSPOLPRACA2";
      case OSOBNIK_ALLD_FITNESS:
        return "ALLD_FITNESS";
      case OSOBNIK_TFT_LOSOWO:
        return "TFT_LOSOWO";
      case OSOBNIK_TFT_WSZYSTO:
        return "TFT_WSZYSTKO";
      case OSOBNIK_TFT_WSPOLPRACA:
        return "TFT_WSPOLPRACA1";
      case OSOBNIK_TFT_WSPOLPRACA2:
        return "TFT_WSPOLPRACA2";
      case OSOBNIK_TFT_FITNESS:
        return "TFT_FITNESS";
      default:
        printf("r=%d\n", r);
        blad("osobnik.nazwa(): Zly rodzaj osobnika.\n");
    }
    return "";
  }

  /*
   * Konstruktor
   * Argumenty:
   * - _n -- informacyjny numer w tablicy populacji
   * - _rodzaj -- informacyjny rodzaj (zmienienie tej wartosci nie musi wplywac na zmiane zachowania)
   * Zalozenia:
   * - aktualny czas(epoka) znajduje sie na zmiennej globalnej time
   */
  osobnik(int _n, int _rodzaj) :
    n(_n),
    rodzaj(_rodzaj),
    utworzony(time),
    strategia(M),
    wyplata(M),
    fitness(0.0)
  {
    switch (REPUTACJA) {
    case REPUTACJA_BRAK:
      reputac = new (reputacja_brak<osobnik>)(this);
      break;

    case REPUTACJA_PODSTAWOWA:
      reputac = new (reputacja_podstawowa<osobnik>)(this);
      break;

	default:
	  blad("wybrano nieznana reputacje!\n");
	  break;
    }

    krawedzie = new real[N];

    timestamp = time - 1;
  }

  /* Destruktor
   * Zalozenia:
   * - krawedzie i reputac sa zaalokowane
   */
  virtual ~osobnik() {
    delete krawedzie;
    delete reputac;
  }

  /*
   * Funkcja obliczajaca nowa strategie w danej turze
   * Zalozenia:
   * - wczesniej zostala wywolana funkcja rozpoczecie_epoki()
   * Wynik:
   * - (real)strategia (albo strategia[0]) to aktualna strategia
   */
  virtual void nowa_strategia() = 0;

  /*
   * Funkcja przygotowywujaca osobnika do nowej epoki
   * Zalozenia:
   * - wczesniej byl wywolany konstruktor albo funkcja zakonczenie_epoki()
   */
  virtual void rozpoczecie_epoki() = 0;

  /*
   * Funkcja wywolywana na zakonczenie epoki
   * Zalozenia:
   * - wczesniej byla wywolana funkcja rozpoczecie_epoki()
   */
  virtual void zakonczenie_epoki() = 0;

  /*
   * Stopien wierzchołka.
   */
  real stopien;
  
  real stopien_wierzcholka() {
		return stopien;
  }

  /*
   * Funkcja wypisujaca osobnika do pliku F, nie dodaje \n na koncu!
   * Argumenty:
   * - F -- otwarty do zapisu plik (np. stdout)
   */
  virtual void wypisz(FILE *F) = 0;
};

extern osobnik **populacja;

class osobnik_allc : public osobnik {
public:
  osobnik_allc();
  ~osobnik_allc();

  osobnik_allc(int);

  void nowa_strategia();
  void rozpoczecie_epoki();
  void zakonczenie_epoki();
  void wypisz(FILE *F);
};

class osobnik_alld : public osobnik {
public:
  osobnik_alld();
  ~osobnik_alld();

  osobnik_alld(int);

  void nowa_strategia();
  void rozpoczecie_epoki();
  void zakonczenie_epoki();
  void wypisz(FILE *F);
};

class osobnik_nietoperz : public osobnik {
public:
  const real s;
  osobnik_nietoperz(int, int, real);

  void nowa_strategia();
  void rozpoczecie_epoki();
  void zakonczenie_epoki();
  void wypisz(FILE *F);
};

class osobnik_nietoperz_zly : public osobnik_nietoperz {
public:
  osobnik_nietoperz_zly(int ktory);
};

class osobnik_nietoperz_dobry : public osobnik_nietoperz {
public:
  osobnik_nietoperz_dobry(int ktory);
};

#endif /* OSOBNIK_H_ */
